Skip to content

Implement Radix Tree#217

Merged
daveshanley merged 4 commits intopb33f:mainfrom
its-hammer-time:implement-radix-tree-for-improved-lookups
Feb 26, 2026
Merged

Implement Radix Tree#217
daveshanley merged 4 commits intopb33f:mainfrom
its-hammer-time:implement-radix-tree-for-improved-lookups

Conversation

@its-hammer-time
Copy link
Contributor

@its-hammer-time its-hammer-time commented Jan 16, 2026

NOTICE

This PR has a subtle breaking change when it comes to identical paths. Refer to the comment below for more info:

https://github.com/pb33f/libopenapi-validator/pull/217/changes#r2700417695

Summary

I noticed some performance issues with the current path matching approach as it recomputes regexes on every validation call. I unfortunately didn't notice the regex cache before making this change, but either way according to my benchmarks this approach is faster and more memory efficient.

The idea is to essentially use a Radix tree for matching the incoming request path against those in the OpenAPI spec to find the appropriate PathItem. The RadixTree will bring the runtime down to O(k) where k is the number of path segments; however, it does not work for the more complex paths (OData, matrix, etc.). So I've essentially made it so we try and run the RadixTree lookup first as I imagine most HTTP urls are simple paths and if that fails we then fall back to the previous approach.

Note that most of the changes in this PR are due to me updating the FindPath function to take in the ValidatorOptions rather than RegexCache directly. I either had to add the Radix tree as a new arg or swap to options so I figured swapping to options would reduce changes in the future if we needed more things later.

Testing

AI wrote all of the tests, but I had it leave all of the previous unit tests except for a couple of outliers:

  1. path_parameter_test.go - The tests that were removed in this file were testing that the RegexCache was appropriately updated for the simple path test case; however, we never hit the cache anymore since the radix handles that case for us. Instead, a new test was added with a supported (simple) and unsupported (OData) path and we test that the unsupported path does have a cache hit.
  2. paths_test.go - Same story here honestly. The only thing that changes is if it was testing the regex cache then we have to move it to an unsupported path. If it's a simple path, none of the tests should have to change, it's backwards compatible. No one should really notice anything is different (except for performance 😄)

@codecov
Copy link

codecov bot commented Jan 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.92%. Comparing base (b8be188) to head (473f875).
⚠️ Report is 37 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #217      +/-   ##
==========================================
+ Coverage   97.86%   97.92%   +0.06%     
==========================================
  Files          60       62       +2     
  Lines        5859     5989     +130     
==========================================
+ Hits         5734     5865     +131     
+ Misses        125      124       -1     
Flag Coverage Δ
unittests 97.92% <100.00%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@its-hammer-time its-hammer-time force-pushed the implement-radix-tree-for-improved-lookups branch from 1d245b8 to 02a6420 Compare January 17, 2026 00:16
@its-hammer-time its-hammer-time marked this pull request as ready for review January 17, 2026 00:26
@its-hammer-time its-hammer-time force-pushed the implement-radix-tree-for-improved-lookups branch 4 times, most recently from d2bfaf7 to f7a0b49 Compare January 20, 2026 22:34
@its-hammer-time its-hammer-time force-pushed the implement-radix-tree-for-improved-lookups branch from f7a0b49 to c4c00c4 Compare January 20, 2026 22:37
@daveshanley
Copy link
Member

daveshanley commented Feb 3, 2026

I came to review this and I see missing coverage and it needs a rebase :)

so I stopped.

Copy link
Member

@daveshanley daveshanley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove deprecated stuff? We need fresh, hot code.. not old cold code.

@daveshanley
Copy link
Member

@its-hammer-time ^^ you coming back on this one?

@its-hammer-time its-hammer-time force-pushed the implement-radix-tree-for-improved-lookups branch from 124aee1 to acfc668 Compare February 23, 2026 20:07
@its-hammer-time
Copy link
Contributor Author

@its-hammer-time ^^ you coming back on this one?

@daveshanley sorry for the delay. Updated those years to 2026 and changed to DisablePathTree(). Not sure if it should be WithDisabledPathTree() cause usually functional options follow With...(), but this one doesn't pass anything in 🤔

Cover WithPathTree, DisablePathTree, IsPathTreeDisabled, and the
FindPath radix tree fast-path branches (method match and mismatch).

Made-with: Cursor
Copy link
Member

@daveshanley daveshanley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@daveshanley daveshanley merged commit 5828615 into pb33f:main Feb 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants